<!DOCTYPE html>
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/dashboard/static/memory_related_names.html">
<link rel="import" href="/tracing/base/base.html">

<script>
'use strict';
tr.exportTo('d', function() {
  /**
   * @typedef {Object} Alert
   * @property {string} testsuite
   * @property {number} start_revision
   * @property {number} end_revision
   */

  /**
   * @param {!Alert} a
   * @param {!Alert} b
   * @return {boolean}
   */
  function shouldMerge(a, b) {
    if (!rangeIntersects(a.start_revision, a.end_revision,
        b.start_revision, b.end_revision)) {
      return false;
    }
    if (!a.relatedNames && !b.relatedNames) return a.testsuite === b.testsuite;
    return isRelated(a, b);
  }

  /**
   * Two Alerts are related if either
   * A) their measurementNames are equal, or
   * B) either's relatedNames contains the other's measurementName.
   *
   * @param {!Alert} a
   * @param {!Alert} b
   * @return {boolean}
   */
  function isRelated(a, b) {
    if (a.measurementName === b.measurementName) return true;
    if (a.relatedNames &&
        a.relatedNames.has(b.measurementName)) {
      return true;
    }
    if (b.relatedNames &&
        b.relatedNames.has(a.measurementName)) {
      return true;
    }
    return false;
  }

  function rangeIntersects(aMin, aMax, bMin, bMax) {
    return aMin <= bMax && bMin <= aMax;
  }

  /**
   * Groups Alerts such that all alerts in each group have overlapping revision
   * ranges and the same test suite.
   *
   * @param {!Array.<!Alert>} alerts
   * @return {!Array.<!Array.<!Alert>>}
   */
  function groupAlerts(alerts) {
    const groups = [];
    const memoryRelatedNames = d.getMemoryRelatedNames();
    for (const alert of alerts) {
      alert.measurementName = alert.test.split('/')[0];
      if (memoryRelatedNames.process.has(alert.measurementName)) {
        alert.relatedNames = memoryRelatedNames.process.get(
            alert.measurementName);
      }
      if (memoryRelatedNames.component.has(alert.measurementName)) {
        alert.relatedNames = new Set(alert.relatedNames);
        for (const name of memoryRelatedNames.component.get(
            alert.measurementName)) {
          alert.relatedNames.add(name);
        }
      }

      let merged = false;
      for (const group of groups) {
        let doMerge = true;
        for (const other of group) {
          const should = shouldMerge(alert, other);
          if (!should) {
            doMerge = false;
            break;
          }
        }
        if (doMerge) {
          group.push(alert);
          merged = true;
          break;
        }
      }

      if (!merged) {
        groups.push([alert]);
      }
    }
    return groups;
  }

  return {
    groupAlerts,
    shouldMerge,
    isRelated,
  };
});
</script>
